// File:       vectorbase.c++
// Version:    1.00
// Author:     (c) Miles Sabin, 1997
// Purpose:    private implementation of vector<T> non-template hoist base class

// Change log:
//  14/01/97   v. 1.00
//             Built from vector<T> 1.00.
//  22/01/97   Bug fix: forgot self-assignment check in operator=().
//             Reimplemented clear().
//  23/02/97   Adapted to HoistHelper/HoistComparator split.
//  04/04/97   Replaced HoistComparators with HoistBinaryPredicates.

#include "vectorbase.h"

#include "algorithm.h"
#include "hoistalgo.h"
#include "hoistbpp.h"
#include "hoistctdtp.h"
#include "memory.h"
#include "newcasts.h"


// Implementation of vector_base

#define size_type             size_t
#define difference_type       ptrdiff_t

vector_base::vector_base(HoistConstructorDestructorProtocol const& hoist_ctdt)
  : hoist_ctdt_(hoist_ctdt)
  { init(); }

vector_base::vector_base(HoistConstructorDestructorProtocol const& hoist_ctdt, size_type n, void const* value)
  : hoist_ctdt_(hoist_ctdt)
  {
    init();
    insert(begin_, n, value);
  }

vector_base::vector_base(HoistConstructorDestructorProtocol const& hoist_ctdt, void const* first, void const* last)
  : hoist_ctdt_(hoist_ctdt)
  {
    init();
    insert(begin_, first, last);
  }

vector_base::vector_base(vector_base const& rhs)
  : hoist_ctdt_(rhs.hoist_ctdt_)
  {
    init();
    insert(begin_, rhs.begin_, rhs.end_);
  }

vector_base::~vector_base()
  {
    HoistAlgorithm::destroy(hoist_ctdt_, begin_, end_);
    ::operator delete(begin_);
  }

size_type vector_base::max_size() const
  { return 1<<24; }

vector_base& vector_base::operator=(vector_base const& rhs)
  {
    if(this == &rhs)
      return *this;

    clear();
    insert(begin_, rhs.begin_, rhs.end_);
    return *this;
  }

void vector_base::assign(void const* first, void const* last)
  {
    clear();
    insert(begin_, first, last);
  }

void vector_base::assign(size_type n, void const* t)
  {
    clear();
    insert(begin_, n, t);
  }

void vector_base::resize(size_type sz, void const* c)
  {
    int change = sz-size();

    if(change > 0)
      insert(end_, change, c);
    else if(change < 0)
      erase(begin_+(sz*elem_size_), end_);
  }

void vector_base::reserve(size_type n)
  {
    if(capacity() >= n)
      return;

    size_type new_capacity = capacity()*2;
    if(new_capacity < n)
      new_capacity = n;

    char* new_begin = reinterpret_cast(char*, ::operator new(new_capacity*elem_size_));;
    HoistAlgorithm::uninitialized_copy(hoist_ctdt_, begin_, end_, new_begin);

    HoistAlgorithm::destroy(hoist_ctdt_, begin_, end_);
    ::operator delete(begin_);

    end_ = new_begin+(size()*elem_size_);
    begin_ = new_begin;
    end_of_storage_ = begin_+(new_capacity*elem_size_);
  }

void vector_base::push_back(void const* x)
  { insert(end_, x); }

void vector_base::pop_back()
  { erase(end_-elem_size_); }

void* vector_base::insert(void* position, void const* x)
  {
    int offset = reinterpret_cast(char*, position)-begin_;
    insert(position, 1, x);
    return begin_+offset;
  }

void vector_base::insert(void* position, size_type n, void const* x)
  {
    if(n == 0)
      return;

    position = insert_aux(position, n);
    HoistAlgorithm::uninitialized_fill(hoist_ctdt_, position, n, x);
  }

void vector_base::insert(void* position, void const* first, void const* last)
  {
    if(first == last)
      return;

    position = insert_aux(position, (reinterpret_cast(char*, last)-reinterpret_cast(char*, first))/elem_size_);
    HoistAlgorithm::uninitialized_copy(hoist_ctdt_, first, last, position);
  }

void vector_base::erase(void* position)
  { erase(position, reinterpret_cast(char*, position)+elem_size_); }

void vector_base::erase(void* first, void* last)
  {
    if(first == last)
      return;

    int erase_size = (reinterpret_cast(char*, last)-reinterpret_cast(char*, first))/elem_size_;
    int new_size = size()-erase_size;

    HoistAlgorithm::copy(hoist_ctdt_, last, end_, first);
    HoistAlgorithm::destroy(hoist_ctdt_, end_-(erase_size*elem_size_), end_);
    end_ = begin_+(new_size*elem_size_);
    size_ -= erase_size;
  }

void vector_base::swap(vector_base& x)
  {
    ::swap(begin_, x.begin_);
    ::swap(end_, x.end_);
    ::swap(end_of_storage_, x.end_of_storage_);
    ::swap(size_, x.size_);
  }

void vector_base::clear()
  {
    HoistAlgorithm::destroy(hoist_ctdt_, begin_, end_);
    end_ = begin_;
    size_ = 0;
  }

void vector_base::init()
  {
    begin_ = 0;
    end_ = 0;
    end_of_storage_ = 0;
    size_ = 0;
    elem_size_ = hoist_ctdt_.size();
  }

void* vector_base::insert_aux(void* position, size_type n)
  {
    int offset = reinterpret_cast(char*, position)-begin_;
    int new_size = size()+n;
    reserve(new_size);
    position = begin_+offset;

    if(position != end_)
    {
      char* move_to = reinterpret_cast(char*, position)+(n*elem_size_);

      if(move_to >= end_)
      {
        HoistAlgorithm::uninitialized_copy(hoist_ctdt_, position, end_, move_to);
        HoistAlgorithm::destroy(hoist_ctdt_, position, end_);
      }
      else
      {
        int overlap = end_-move_to;

        HoistAlgorithm::uninitialized_copy(hoist_ctdt_, reinterpret_cast(char*, position)+overlap, end_, end_);
        HoistAlgorithm::copy_backward(hoist_ctdt_, position, reinterpret_cast(char*, position)+overlap, end_);
        HoistAlgorithm::destroy(hoist_ctdt_, position, move_to);
      }
    }

    end_ = begin_+(new_size*elem_size_);
    size_ += n;
    return position;
  }

bool vector_base::is_equal(HoistBinaryPredicateProtocol const& hoist_comparator, vector_base const& rhs) const
  {
    return size() == rhs.size() && HoistAlgorithm::equal(hoist_ctdt_, hoist_comparator, begin_, end_, rhs.begin_);
  }

bool vector_base::is_less_than(HoistBinaryPredicateProtocol const& hoist_comparator, vector_base const& rhs) const
  {
    return HoistAlgorithm::lexicographical_compare(hoist_ctdt_, hoist_comparator, begin_, end_, rhs.begin_, rhs.end_);
  }

#undef size_type
#undef difference_type


